package com.pb.wkflow.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.pb.infra.oth.util.SpringContextUtil;
import com.pb.wkflow.api.exception.ApprovalException;
import com.pb.wkflow.core.camunda.bpmn.instance.Participants;
import com.pb.wkflow.core.camunda.bpmn.instance.RuleLogicParam;
import com.pb.wkflow.core.camunda.bpmn.instance.UserParticipant;
import com.pb.wkflow.core.entity.PostInfo;
import com.pb.wkflow.core.service.IHttpParticipantService;
import com.pb.wkflow.core.service.IwkfParticipantService;
import com.pb.wkflow.core.service.UserParticipantService;
import com.pb.wkflow.core.service.WorkflowService;
import com.pb.wkflow.core.utils.ArrayUtils;
import com.pb.wkflow.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.delegate.DelegateTask;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricActivityInstanceQuery;
import org.camunda.bpm.engine.impl.persistence.entity.TaskEntity;
import org.camunda.bpm.model.bpmn.instance.UserTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 *
 * @author 苗益辉
 * @date 2022/5/16 11:04
 */
@Slf4j
@Service
public class WorkflowServiceImpl implements WorkflowService {

    @Autowired
    UserParticipantService userParticipantService;

    @Autowired
    HistoryService historyService;

    /**
     * 添加参与者
     * 类型 1  流程参与者
     * 类型 2 流程发起者 获取流程变量中的startUserId
     * 类型 3 流程执行者 获取历史活动的处理人
     * 类型 4 相关数据 根据参数从流程变量中获取数据
     * 类型 5 规则逻辑 调用内部服务或者外部链接
     * @param taskEntity taskEntity
     */
    @Override
    public void addParticipantUser(TaskEntity taskEntity) {
        UserParticipant userParticipant = taskEntity.getBpmnModelElementInstance()
                .getExtensionElements().getElementsQuery().filterByType(UserParticipant.class).singleResult();
        String participantType = userParticipant.getParticipantType();
        log.info("TaskEventListener 当前节点参与者类型：{}", participantType);
        if(UserParticipant.CONFIG_TYPE_1.equals(participantType)) {
            //流程参与者
            List<PostInfo> postInfos = getParticipantType1(userParticipant,taskEntity);
            userParticipantService.saveUserTaskAssignment(taskEntity, postInfos);
        } else if (UserParticipant.CONFIG_TYPE_2.equals(participantType)) {
            //流程发起者
            String startUserId = getParticipantType2(taskEntity);
            userParticipantService.saveUserTaskAssignment(taskEntity, startUserId);
        } else if (UserParticipant.CONFIG_TYPE_3.equals(participantType)) {
            Set<String> userIds = getParticipantType3(userParticipant,taskEntity);
            userParticipantService.saveUserTaskAssignment(taskEntity, userIds.toArray(new String[userIds.size()]));
        } else if (UserParticipant.CONFIG_TYPE_4.equals(participantType)) {
            //相关数据
            Object aboutDataValue = getParticipantType4(userParticipant, taskEntity);
            if(aboutDataValue instanceof String) {
                userParticipantService.saveUserTaskAssignment(taskEntity, (String) aboutDataValue);
            }else if (aboutDataValue instanceof PostInfo) {
                PostInfo postInfo = (PostInfo) aboutDataValue;
                userParticipantService.saveUserTaskAssignment(taskEntity,postInfo);
            }else if (aboutDataValue instanceof List) {
                userParticipantService.saveUserTaskAssignment(taskEntity,(List<PostInfo>) aboutDataValue);
            }else {
                throw new ApprovalException("找不到相关数据");
            }
        } else if (UserParticipant.CONFIG_TYPE_5.equals(participantType)) {
            List<PostInfo> postInfos = getParticipantType5(userParticipant, taskEntity);
            if(postInfos.isEmpty()) {
                throw new ApprovalException("规则逻辑找不到处理人");
            }
            userParticipantService.saveUserTaskAssignment(taskEntity,postInfos);
        }
    }

    @Override
    public List<PostInfo> getParticipantType1(UserParticipant userParticipant, TaskEntity taskEntity) {
        Collection<Participants> participantsCollection = userParticipant.getParticipants();
        if(participantsCollection.isEmpty()) {
            throw new ApprovalException("未配置流程参与者");
        }
        List<PostInfo> postInfos = new ArrayList<>();
        for(Participants participants : participantsCollection) {
            PostInfo postInfo = PostInfo.builder().build();
            userParticipantService.getParticipants(participants,postInfo,taskEntity.getVariables());
            postInfos.add(postInfo);
        }
        return postInfos;
    }

    @Override
    public String getParticipantType2(DelegateTask delegateTask) {
        String startUserId = (String) delegateTask.getVariables().get("startUserId");
        if(StringUtils.isBlank(startUserId)) {
            throw new ApprovalException("流程发起者-发起人为空");
        }
        return startUserId;
    }

    @Override
    public Set<String> getParticipantType3(UserParticipant userParticipant, TaskEntity taskEntity) {
        String activityId = userParticipant.getActivity();
        //历史活动
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        List<HistoricActivityInstance> historicActivityInstances = historicActivityInstanceQuery
                .processInstanceId(taskEntity.getProcessInstanceId()).activityId(activityId)
                .orderByHistoricActivityInstanceEndTime().desc().list();
        if(ArrayUtils.isEmpty(historicActivityInstances)) {
            throw new ApprovalException("流程执行者-找不到指定活动");
        }
        HistoricActivityInstance historicActivityInstance = historicActivityInstances.get(0);
        //如果历史节点是会签
        UserTask userTask = taskEntity.getBpmnModelInstance().getModelElementById(historicActivityInstance.getActivityId());
        if(userTask.getLoopCharacteristics() != null) {
            String parentActivityInstanceId = historicActivityInstance.getParentActivityInstanceId();
            Set<String> userIds = new HashSet<>();
            for (HistoricActivityInstance activityInstance : historicActivityInstances) {
                if (StringUtils.equals(parentActivityInstanceId, activityInstance.getParentActivityInstanceId())) {
                    userIds.add(activityInstance.getAssignee());
                }
            }
            return userIds;
        }else {
            Set<String> set = new HashSet<>();
            set.add(historicActivityInstance.getAssignee());
            return set;
        }
    }

    @Override
    public Object getParticipantType4(UserParticipant userParticipant, TaskEntity taskEntity) {
        String aboutData = userParticipant.getAboutData();
        String aboutDataKey = aboutData.substring(aboutData.indexOf("${") + 2, aboutData.indexOf("}", aboutData.indexOf("}")));
        Object aboutDataValue = taskEntity.getVariables().get(aboutDataKey);
        if(aboutDataValue instanceof String) {
            return aboutDataValue;
        }else if (aboutDataValue instanceof Map) {
            String dataString = JSON.toJSONString(aboutDataValue);
            return JSON.parseObject(dataString, PostInfo.class);
        }else if (aboutDataValue instanceof PostInfo) {
            return aboutDataValue;
        }else if (aboutDataValue instanceof List) {
            String dataString = JSON.toJSONString(aboutDataValue);
            return JSON.parseArray(dataString, PostInfo.class);
        }
        return null;
    }

    @Override
    public List<PostInfo> getParticipantType5(UserParticipant userParticipant, TaskEntity taskEntity) {
        String serviceType = userParticipant.getServiceType();
        Collection<RuleLogicParam> ruleLogicParams = userParticipant.getRuleLoginParam();
        Map<String, Object> params = new HashMap<>(2);
        for(RuleLogicParam ruleLogicParam : ruleLogicParams) {
            if(RuleLogicParam.TYPE_CONSTANT.equals(ruleLogicParam.getType())) {
                params.put(ruleLogicParam.getParam(), ruleLogicParam.getValue());
            }else if(RuleLogicParam.TYPE_VARIABLES.equals(ruleLogicParam.getType())) {
                params.put(ruleLogicParam.getParam(), taskEntity.getVariables().get(ruleLogicParam.getParam()));
            }
        }
        List<PostInfo> postInfos = new ArrayList<>();
        if(UserParticipant.SERVICE_TYPE_LOCAL.equals(serviceType)) {
            String serviceBean = userParticipant.getServiceBean();
            if(StringUtils.isBlank(serviceBean)) {
                throw new ApprovalException("内部服务不能为空");
            }
            IwkfParticipantService workflowParticipantService = SpringContextUtil.getBean(serviceBean, IwkfParticipantService.class);
            postInfos = workflowParticipantService.execute(params);
        }else if(UserParticipant.SERVICE_TYPE_ONLINE.equals(serviceType)) {
            String serviceUrl = userParticipant.getServiceUrl();
            if(StringUtils.isBlank(serviceUrl)) {
                throw new ApprovalException("外部服务地址不能为空");
            }
            IHttpParticipantService httpParticipantService = SpringContextUtil.getBean(IHttpParticipantService.class);
            postInfos = httpParticipantService.execute(serviceUrl, params);
        }
        return postInfos;
    }
}
